From: iap10@tetris.cl.cam.ac.uk Date: Tue, 30 Mar 2004 15:44:27 +0000 (+0000) Subject: bitkeeper revision 1.831 (406995dbwlqGk2qHrfw3kwGxQ37WSw) X-Git-Tag: archive/raspbian/4.8.0-1+rpi1~1^2~18290 X-Git-Url: https://dgit.raspbian.org/%22http:/www.example.com/cgi/%22https://%22%22/%22http:/www.example.com/cgi/%22https:/%22%22?a=commitdiff_plain;h=4e40b35e723ddf9fbca88499bb5c089684209b6d;p=xen.git bitkeeper revision 1.831 (406995dbwlqGk2qHrfw3kwGxQ37WSw) Flush and clean shadow page table ops added. Add 'dist' target back to Xen Makefile. --- diff --git a/tools/xc/py/Xc.c b/tools/xc/py/Xc.c index 96b9bf491a..4c82b03d73 100644 --- a/tools/xc/py/Xc.c +++ b/tools/xc/py/Xc.c @@ -914,6 +914,28 @@ static PyObject *pyxc_rrobin_global_set(PyObject *self, return zero; } +static PyObject *pyxc_shadow_control(PyObject *self, + PyObject *args, + PyObject *kwds) +{ + XcObject *xc = (XcObject *)self; + + u64 dom; + int op=0; + + static char *kwd_list[] = { "dom", "op", NULL }; + + if ( !PyArg_ParseTupleAndKeywords(args, kwds, "L|i", kwd_list, + &dom, &op) ) + return NULL; + + if ( xc_shadow_control(xc->xc_handle, dom, op) != 0 ) + return PyErr_SetFromErrno(xc_error); + + Py_INCREF(zero); + return zero; +} + static PyMethodDef pyxc_methods[] = { { "domain_create", @@ -1211,6 +1233,15 @@ static PyMethodDef pyxc_methods[] = { "Returns [dict]: information about the hardware" " [None]: on failure.\n" }, + { "shadow_control", + (PyCFunction)pyxc_shadow_control, + METH_VARARGS | METH_KEYWORDS, "\n" + "Set parameter for shadow pagetable interface\n" + " dom [long]: Identifier of domain.\n" + " op [int, 0]: operation\n\n" + "Returns: [int] 0 on success; -1 on error.\n" }, + + { NULL, NULL, 0, NULL } }; diff --git a/xen/Makefile b/xen/Makefile index e887dd2235..cfe5e1242c 100644 --- a/xen/Makefile +++ b/xen/Makefile @@ -22,6 +22,9 @@ install: $(TARGET) mkdir -p $(prefix)/boot install -m0644 $(TARGET).gz $(prefix)/boot +dist: $(TARGET) + $(MAKE) prefix=`pwd`/../../install dist=yes install + clean: delete-links $(MAKE) -C tools clean $(MAKE) -C common clean diff --git a/xen/common/shadow.c b/xen/common/shadow.c index dc6705ab19..600f8211f4 100644 --- a/xen/common/shadow.c +++ b/xen/common/shadow.c @@ -26,54 +26,138 @@ hypercall lock anyhow (at least initially). ********/ -static inline void free_shadow_page( struct mm_struct *m, unsigned int pfn ) +static inline void free_shadow_page( struct mm_struct *m, + struct pfn_info *pfn_info ) { unsigned long flags; + unsigned long type = pfn_info->type_and_flags & PGT_type_mask; m->shadow_page_count--; + if (type == PGT_l1_page_table) + perfc_decr(shadow_l1_pages); + else if (type == PGT_l2_page_table) + perfc_decr(shadow_l2_pages); + else printk("Free shadow weird page type pfn=%08x type=%08lx\n", + frame_table-pfn_info, pfn_info->type_and_flags); + + + pfn_info->type_and_flags = 0; + spin_lock_irqsave(&free_list_lock, flags); - list_add(&frame_table[pfn].list, &free_list); + list_add(&pfn_info->list, &free_list); free_pfns++; spin_unlock_irqrestore(&free_list_lock, flags); } static void __free_shadow_table( struct mm_struct *m ) { - int j; - struct shadow_status *a; + int j, free=0; + struct shadow_status *a,*next; // the code assumes you're not using the page tables i.e. // the domain is stopped and cr3 is something else!! // walk the hash table and call free_shadow_page on all pages + shadow_audit(m,1); + for(j=0;jshadow_ht[j]; if (a->pfn) { - free_shadow_page( m, a->spfn_and_flags & PSH_pfn_mask ); + free_shadow_page( m, + &frame_table[a->spfn_and_flags & PSH_pfn_mask] ); a->pfn = 0; a->spfn_and_flags = 0; + free++; } - a=a->next; + next=a->next; + a->next=NULL; + a=next; while(a) { struct shadow_status *next = a->next; - free_shadow_page( m, a->spfn_and_flags & PSH_pfn_mask ); + + free_shadow_page( m, + &frame_table[a->spfn_and_flags & PSH_pfn_mask] ); a->pfn = 0; a->spfn_and_flags = 0; - a->next = m->shadow_ht_free; + free++; + a->next = m->shadow_ht_free; m->shadow_ht_free = a; a=next; } + shadow_audit(m,0); } + SH_LOG("Free shadow table. Freed= %d",free); } +static inline int shadow_page_op( struct mm_struct *m, unsigned int op, + struct pfn_info *spfn_info ) +{ + int work = 0; + unsigned int spfn = spfn_info-frame_table; -int shadow_mode_enable( struct mm_struct *m, unsigned int mode ) + switch( op ) + { + case DOM0_SHADOW_CONTROL_OP_CLEAN: + { + int i; + if ( (spfn_info->type_and_flags & PGT_type_mask) == + PGT_l1_page_table ) + { + unsigned long * spl1e = map_domain_mem( spfn<shadow_ht[j]; + if (a->pfn) + { + work += shadow_page_op( m, op, &frame_table[a->spfn_and_flags & PSH_pfn_mask] ); + } + a=a->next; + while(a) + { + work += shadow_page_op( m, op, &frame_table[a->spfn_and_flags & PSH_pfn_mask] ); + a=a->next; + } + shadow_audit(m,0); + } + SH_LOG("Scan shadow table. Work=%d l1=%d l2=%d", work, perfc_value(shadow_l1_pages), perfc_value(shadow_l2_pages)); +} + + +int shadow_mode_enable( struct task_struct *p, unsigned int mode ) +{ + struct mm_struct *m = &p->mm; struct shadow_status **fptr; int i; @@ -102,6 +186,8 @@ int shadow_mode_enable( struct mm_struct *m, unsigned int mode ) memset( m->shadow_ht_extras, 0, sizeof(void*) + (shadow_ht_extra_size * sizeof(struct shadow_status)) ); + + m->shadow_extras_count++; // add extras to free list fptr = &m->shadow_ht_free; @@ -114,6 +200,13 @@ int shadow_mode_enable( struct mm_struct *m, unsigned int mode ) *((struct shadow_status ** ) &m->shadow_ht_extras[shadow_ht_extra_size]) = NULL; + if ( mode == SHM_logdirty ) + { + m->shadow_dirty_bitmap = kmalloc( p->max_pages/8, GFP_KERNEL ); + if( !m->shadow_dirty_bitmap ) goto nomem; + memset(m->shadow_dirty_bitmap,0,p->max_pages/8); + } + spin_unlock(&m->shadow_lock); // call shadow_mk_pagetable @@ -126,16 +219,43 @@ nomem: return -ENOMEM; } -static void shadow_mode_disable( struct mm_struct *m ) +static void shadow_mode_disable( struct task_struct *p ) { + struct mm_struct *m = &p->mm; + struct shadow_status *next; + + spin_lock(&m->shadow_lock); + __free_shadow_table( m ); + m->shadow_mode = 0; + spin_unlock(&m->shadow_lock); + + SH_LOG("freed tables count=%d l1=%d l2=%d", + m->shadow_page_count, perfc_value(shadow_l1_pages), perfc_value(shadow_l2_pages)); + + next = m->shadow_ht_extras; + while( next ) + { + struct shadow_status * this = next; + m->shadow_extras_count--; + next = *((struct shadow_status **)(&next[shadow_ht_extra_size])); + kfree( this ); + } - // free the hash buckets as you go + SH_LOG("freed extras, now %d", m->shadow_extras_count); + + if( m->shadow_dirty_bitmap ) + { + kfree( m->shadow_dirty_bitmap ); + m->shadow_dirty_bitmap = 0; + } // free the hashtable itself + kfree( &m->shadow_ht[0] ); } -static void shadow_mode_flush( struct mm_struct *m ) +static void shadow_mode_table_op( struct task_struct *p, unsigned int op ) { + struct mm_struct *m = &p->mm; // since Dom0 did the hypercall, we should be running with it's page // tables right now. Calling flush on yourself would be really @@ -147,10 +267,32 @@ static void shadow_mode_flush( struct mm_struct *m ) return; } + spin_lock(&m->shadow_lock); - __free_shadow_table( m ); + + SH_LOG("shadow mode table op %08lx %08lx count %d",pagetable_val( m->pagetable),pagetable_val(m->shadow_table), m->shadow_page_count); + + shadow_audit(m,1); + + switch(op) + { + case DOM0_SHADOW_CONTROL_OP_FLUSH: + __free_shadow_table( m ); + break; + + case DOM0_SHADOW_CONTROL_OP_CLEAN: + __scan_shadow_table( m, op ); + if( m->shadow_dirty_bitmap ) + memset(m->shadow_dirty_bitmap,0,p->max_pages/8); + break; + } + spin_unlock(&m->shadow_lock); + SH_LOG("shadow mode table op : page count %d", m->shadow_page_count); + + shadow_audit(m,1); + // call shadow_mk_pagetable shadow_mk_pagetable( m ); @@ -164,28 +306,30 @@ int shadow_mode_control( struct task_struct *p, unsigned int op ) // don't call if already shadowed... // sychronously stop domain - if( !(p->state & TASK_STOPPED) && !(p->state & TASK_PAUSED)) + if( 0 && !(p->state & TASK_STOPPED) && !(p->state & TASK_PAUSED)) { + printk("about to pause domain\n"); sched_pause_sync(p); printk("paused domain\n"); we_paused = 1; } - if (p->mm.shadow_mode && op == DOM0_SHADOW_CONTROL_OP_OFF ) + if ( p->mm.shadow_mode && op == DOM0_SHADOW_CONTROL_OP_OFF ) { - shadow_mode_disable(&p->mm); + shadow_mode_disable(p); } - else if (p->mm.shadow_mode && op == DOM0_SHADOW_CONTROL_OP_ENABLE_TEST ) + else if ( op == DOM0_SHADOW_CONTROL_OP_ENABLE_TEST ) { - shadow_mode_disable(&p->mm); - shadow_mode_enable(&p->mm, SHM_test); + if(p->mm.shadow_mode) shadow_mode_disable(p); + shadow_mode_enable(p, SHM_test); } - else if (p->mm.shadow_mode && op == DOM0_SHADOW_CONTROL_OP_FLUSH ) + else if ( p->mm.shadow_mode && op >= DOM0_SHADOW_CONTROL_OP_FLUSH && op<=DOM0_SHADOW_CONTROL_OP_CLEAN ) { - shadow_mode_flush(&p->mm); + shadow_mode_table_op(p, op); } else { + if ( we_paused ) wake_up(p); return -EINVAL; } @@ -220,6 +364,7 @@ void unshadow_table( unsigned long gpfn, unsigned int type ) // this CPU was the one that cmpxchg'ed the page to invalid spfn = __shadow_status(¤t->mm, gpfn) & PSH_pfn_mask; + delete_shadow_status(¤t->mm, gpfn); #if 0 // XXX leave as might be useful for later debugging @@ -235,12 +380,7 @@ void unshadow_table( unsigned long gpfn, unsigned int type ) } #endif - if (type == PGT_l1_page_table) - perfc_decr(shadow_l1_pages); - else - perfc_decr(shadow_l2_pages); - - free_shadow_page( ¤t->mm, spfn ); + free_shadow_page( ¤t->mm, &frame_table[spfn] ); } @@ -256,7 +396,6 @@ unsigned long shadow_l2_table( SH_VVLOG("shadow_l2_table( %08lx )",gpfn); perfc_incrc(shadow_l2_table_count); - perfc_incr(shadow_l2_pages); // XXX in future, worry about racing in SMP guests // -- use cmpxchg with PSH_pending flag to show progress (and spin) @@ -265,6 +404,9 @@ unsigned long shadow_l2_table( ASSERT( spfn_info ); // XXX deal with failure later e.g. blow cache + spfn_info->type_and_flags = PGT_l2_page_table; + perfc_incr(shadow_l2_pages); + spfn = (unsigned long) (spfn_info - frame_table); // mark pfn as being shadowed, update field to point at shadow @@ -434,7 +576,9 @@ int shadow_fault( unsigned long va, long error_code ) struct pfn_info *sl1pfn_info; unsigned long *gpl1e, *spl1e; int i; - sl1pfn_info = alloc_domain_page( NULL ); // XXX account properly! + sl1pfn_info = alloc_shadow_page( ¤t->mm ); + sl1pfn_info->type_and_flags = PGT_l1_page_table; + sl1pfn = sl1pfn_info - frame_table; SH_VVLOG("4a: l1 not shadowed ( %08lx )",sl1pfn); diff --git a/xen/include/asm-i386/processor.h b/xen/include/asm-i386/processor.h index 60c70d9037..b7aa895bfd 100644 --- a/xen/include/asm-i386/processor.h +++ b/xen/include/asm-i386/processor.h @@ -426,8 +426,10 @@ struct mm_struct { struct shadow_status *shadow_ht; struct shadow_status *shadow_ht_free; struct shadow_status *shadow_ht_extras; // extra allocation units + unsigned int *shadow_dirty_bitmap; unsigned int shadow_page_count; unsigned int shadow_max_page_count; + unsigned int shadow_extras_count; /* Current LDT details. */ unsigned long ldt_base, ldt_ents, shadow_ldt_mapcnt; diff --git a/xen/include/hypervisor-ifs/dom0_ops.h b/xen/include/hypervisor-ifs/dom0_ops.h index f3f93a289e..70cf92225b 100644 --- a/xen/include/hypervisor-ifs/dom0_ops.h +++ b/xen/include/hypervisor-ifs/dom0_ops.h @@ -221,7 +221,9 @@ typedef struct dom0_pcidev_access_st #define DOM0_SHADOW_CONTROL_OP_OFF 0 #define DOM0_SHADOW_CONTROL_OP_ENABLE_TEST 1 +#define DOM0_SHADOW_CONTROL_OP_ENABLE_LOGDIRTY 2 #define DOM0_SHADOW_CONTROL_OP_FLUSH 10 +#define DOM0_SHADOW_CONTROL_OP_CLEAN 11 typedef struct dom0_shadow_control_st { /* IN variables. */ diff --git a/xen/include/xen/shadow.h b/xen/include/xen/shadow.h index a9d03b4198..0f4e2e19d4 100644 --- a/xen/include/xen/shadow.h +++ b/xen/include/xen/shadow.h @@ -15,10 +15,10 @@ #define PSH_pfn_mask ((1<<21)-1) /* Shadow PT operation mode : shadowmode variable in mm_struct */ -#define SHM_test (1<<0) /* just run domain on shadow PTs */ -#define SHM_logdirty (1<<1) /* log pages that are dirtied */ -#define SHM_cow (1<<2) /* copy on write all dirtied pages */ -#define SHM_translate (1<<3) /* lookup machine pages in translation table */ +#define SHM_test (1) /* just run domain on shadow PTs */ +#define SHM_logdirty (2) /* log pages that are dirtied */ +#define SHM_cow (3) /* copy on write all dirtied pages */ +#define SHM_translate (4) /* lookup machine pages in translation table */ #define shadow_linear_pg_table ((l1_pgentry_t *)SH_LINEAR_PT_VIRT_START) #define shadow_linear_l2_table ((l2_pgentry_t *)(SH_LINEAR_PT_VIRT_START+(SH_LINEAR_PT_VIRT_START>>(L2_PAGETABLE_SHIFT-L1_PAGETABLE_SHIFT)))) @@ -30,7 +30,7 @@ extern void shadow_l1_normal_pt_update( unsigned long pa, unsigned long gpte, l1_pgentry_t **prev_spl1e_ptr ); extern void shadow_l2_normal_pt_update( unsigned long pa, unsigned long gpte ); extern void unshadow_table( unsigned long gpfn, unsigned int type ); -extern int shadow_mode_enable( struct mm_struct *m, unsigned int mode ); +extern int shadow_mode_enable( struct task_struct *p, unsigned int mode ); extern unsigned long shadow_l2_table( struct mm_struct *m, unsigned long gpfn ); @@ -81,26 +81,33 @@ static void shadow_audit(struct mm_struct *m, int print) for(j=0;jmm.shadow_ht[j]; - if(a->pfn) live++; - while(a->next && live<9999) + a = &m->shadow_ht[j]; + if(a->pfn){live++; ASSERT(a->spfn_and_flags&PSH_pfn_mask);} + ASSERT((a->pfn&0xf0000000)==0); + ASSERT(a->pfn<0x00100000); + a=a->next; + while(a && live<9999) { live++; - if(a->pfn == 0) + if(a->pfn == 0 || a->spfn_and_flags == 0) { printk("XXX live=%d pfn=%08lx sp=%08lx next=%p\n", live, a->pfn, a->spfn_and_flags, a->next); BUG(); } + ASSERT(a->pfn); + ASSERT((a->pfn&0xf0000000)==0); + ASSERT(a->pfn<0x00100000); + ASSERT(a->spfn_and_flags&PSH_pfn_mask); a=a->next; } ASSERT(live<9999); } - a = p->mm.shadow_ht_free; + a = m->shadow_ht_free; while(a) { free++; a=a->next; } - if(print) printk("live=%d free=%d\n",live,free); + if(print) printk("Xlive=%d free=%d\n",live,free); abs=(perfc_value(shadow_l1_pages)+perfc_value(shadow_l2_pages))-live; if( abs < -1 || abs > 1 ) @@ -214,6 +221,8 @@ static inline void delete_shadow_status( struct mm_struct *m, b->next = b->next->next; D->next = m->shadow_ht_free; + D->pfn = 0; + D->spfn_and_flags = 0; m->shadow_ht_free = D; } else @@ -224,6 +233,7 @@ static inline void delete_shadow_status( struct mm_struct *m, #if SHADOW_HASH_DEBUG if( __shadow_status(m,gpfn) ) BUG(); + shadow_audit(m,0); #endif return; } @@ -246,6 +256,7 @@ static inline void delete_shadow_status( struct mm_struct *m, #if SHADOW_HASH_DEBUG if( __shadow_status(m,gpfn) ) BUG(); #endif + shadow_audit(m,0); return; } @@ -268,8 +279,10 @@ static inline void set_shadow_status( struct mm_struct *m, B = b = hash_bucket( m, gpfn ); ASSERT(gpfn); - ASSERT(s); + //ASSERT(s); + //ASSERT(s&PSH_pfn_mask); SH_VVLOG("set gpfn=%08x s=%08lx bucket=%p(%p)", gpfn, s, b, b->next ); + shadow_audit(m,0); do @@ -277,6 +290,7 @@ static inline void set_shadow_status( struct mm_struct *m, if ( b->pfn == gpfn ) { b->spfn_and_flags = s; + shadow_audit(m,0); return; } @@ -294,6 +308,7 @@ static inline void set_shadow_status( struct mm_struct *m, ASSERT( B->next == 0 ); B->pfn = gpfn; B->spfn_and_flags = s; + shadow_audit(m,0); return; } @@ -309,6 +324,8 @@ static inline void set_shadow_status( struct mm_struct *m, memset( extra, 0, sizeof(void*) + (shadow_ht_extra_size * sizeof(struct shadow_status)) ); + + m->shadow_extras_count++; // add extras to free list fptr = &m->shadow_ht_free; @@ -319,7 +336,7 @@ static inline void set_shadow_status( struct mm_struct *m, } *fptr = NULL; - *((struct shadow_status ** ) &m->shadow_ht[shadow_ht_extra_size]) = + *((struct shadow_status ** ) &extra[shadow_ht_extra_size]) = m->shadow_ht_extras; m->shadow_ht_extras = extra; @@ -333,6 +350,8 @@ static inline void set_shadow_status( struct mm_struct *m, b->next = B->next; B->next = b; + shadow_audit(m,0); + return; }